if ( pagetable_val(ed->arch.shadow_table) )
adjust(&frame_table[pagetable_val(ed->arch.shadow_table)
>> PAGE_SHIFT], 0);
+ if ( ed->arch.monitor_shadow_ref )
+ adjust(&frame_table[ed->arch.monitor_shadow_ref], 0);
}
}
}
put_page(&frame_table[old_base_mfn]);
else
put_page_and_type(&frame_table[old_base_mfn]);
+
+ // CR3 holds its own ref to its shadow...
+ //
+ if ( shadow_mode_enabled(d) )
+ {
+ if ( ed->arch.monitor_shadow_ref )
+ put_shadow_ref(ed->arch.monitor_shadow_ref);
+ ed->arch.monitor_shadow_ref =
+ pagetable_val(ed->arch.monitor_table) >> PAGE_SHIFT;
+ ASSERT(page_get_owner(&frame_table[ed->arch.monitor_shadow_ref]) == NULL);
+ get_shadow_ref(ed->arch.monitor_shadow_ref);
+ }
}
else
{
break;
case MMUEXT_INVLPG:
- __flush_tlb_one(ptr);
if ( shadow_mode_enabled(d) )
shadow_invlpg(ed, ptr);
+ __flush_tlb_one(ptr);
break;
case MMUEXT_FLUSH_CACHE:
if ( deferred_ops & DOP_FLUSH_TLB )
{
- local_flush_tlb();
if ( shadow_mode_enabled(d) )
shadow_sync_all(d);
+ local_flush_tlb();
}
if ( deferred_ops & DOP_RELOAD_LDT )
if ( unlikely(deferred_ops & DOP_FLUSH_TLB) ||
unlikely(flags & UVMF_FLUSH_TLB) )
{
- local_flush_tlb();
if ( unlikely(shadow_mode_enabled(d)) )
shadow_sync_all(d);
+ local_flush_tlb();
}
else if ( unlikely(flags & UVMF_INVLPG) )
{
- __flush_tlb_one(va);
if ( unlikely(shadow_mode_enabled(d)) )
shadow_invlpg(current, va);
+ __flush_tlb_one(va);
}
if ( unlikely(deferred_ops & DOP_RELOAD_LDT) )
if ( unlikely(page_is_page_table(page)) )
return 1;
- FSH_LOG("shadow_promote gpfn=%p gmfn=%p nt=%p", gpfn, gmfn, new_type);
+ FSH_LOG("%s: gpfn=%p gmfn=%p nt=%p", __func__, gpfn, gmfn, new_type);
if ( !shadow_remove_all_write_access(d, gpfn, gmfn) )
+ {
+ FSH_LOG("%s: couldn't find/remove all write accesses, gpfn=%p gmfn=%p\n",
+ __func__, gpfn, gmfn);
return 0;
+ }
// To convert this page to use as a page table, the writable count
// should now be zero. Test this by grabbing the page as an page table,
{
unsigned long hl2mfn;
l1_pgentry_t *hl2;
- l2_pgentry_t *gl2;
- int i, limit;
+ int limit;
ASSERT(PGT_base_page_table == PGT_l2_page_table);
perfc_incrc(shadow_hl2_table_count);
- gl2 = map_domain_mem(gmfn << PAGE_SHIFT);
hl2 = map_domain_mem(hl2mfn << PAGE_SHIFT);
if ( shadow_mode_external(d) )
else
limit = DOMAIN_ENTRIES_PER_L2_PAGETABLE;
- for ( i = 0; i < limit; i++ )
- {
- unsigned long gl2e = l2_pgentry_val(gl2[i]);
- unsigned long hl2e;
-
- hl2e_propagate_from_guest(d, gl2e, &hl2e);
-
- if ( (hl2e & _PAGE_PRESENT) &&
- !get_page(pfn_to_page(hl2e >> PAGE_SHIFT), d) )
- hl2e = 0;
-
- hl2[i] = mk_l1_pgentry(hl2e);
- }
+ memset(hl2, 0, limit * sizeof(l1_pgentry_t));
if ( !shadow_mode_external(d) )
{
}
unmap_domain_mem(hl2);
- unmap_domain_mem(gl2);
return hl2mfn;
}
l2_pgentry_t *monitor_vtable; /* virtual address of monitor_table */
l1_pgentry_t *hl2_vtable; /* virtual address of hl2_table */
+ unsigned long monitor_shadow_ref;
+
/* Virtual CR2 value. Can be read/written by guest. */
unsigned long guest_cr2;
static inline unsigned long __shadow_status(
struct domain *d, unsigned long gpfn, unsigned long stype);
+static inline void update_hl2e(struct exec_domain *ed, unsigned long va);
extern void vmx_shadow_clear_state(struct domain *);
//
__shadow_sync_all(ed->domain);
}
+
+ // Also make sure the HL2 is up-to-date for this address.
+ //
+ if ( unlikely(shadow_mode_translate(ed->domain)) )
+ update_hl2e(ed, va);
}
static void inline
__guest_set_l2e(
struct exec_domain *ed, unsigned long va, unsigned long value)
{
+ ed->arch.guest_vtable[l2_table_offset(va)] = mk_l2_pgentry(value);
+
if ( unlikely(shadow_mode_translate(ed->domain)) )
- {
- unsigned long mfn = phys_to_machine_mapping(value >> PAGE_SHIFT);
- unsigned long old_hl2e =
- l1_pgentry_val(ed->arch.hl2_vtable[l2_table_offset(va)]);
- unsigned long new_hl2e =
- (VALID_MFN(mfn) ? ((mfn << PAGE_SHIFT) | __PAGE_HYPERVISOR) : 0);
+ update_hl2e(ed, va);
+}
- // only do the ref counting if something important changed.
- //
- if ( (old_hl2e ^ new_hl2e) & (PAGE_MASK | _PAGE_PRESENT) )
+static inline void
+update_hl2e(struct exec_domain *ed, unsigned long va)
+{
+ int index = l2_table_offset(va);
+ unsigned long gl2e = l2_pgentry_val(ed->arch.guest_vtable[index]);
+ unsigned long mfn;
+ unsigned long old_hl2e, new_hl2e;
+ int need_flush = 0;
+
+ ASSERT(shadow_mode_translate(ed->domain));
+
+ old_hl2e = l1_pgentry_val(ed->arch.hl2_vtable[index]);
+
+ if ( (gl2e & _PAGE_PRESENT) &&
+ VALID_MFN(mfn = phys_to_machine_mapping(gl2e >> PAGE_SHIFT)) )
+ new_hl2e = (mfn << PAGE_SHIFT) | __PAGE_HYPERVISOR;
+ else
+ new_hl2e = 0;
+
+ // only do the ref counting if something important changed.
+ //
+ if ( (old_hl2e ^ new_hl2e) & (PAGE_MASK | _PAGE_PRESENT) )
+ {
+ if ( (new_hl2e & _PAGE_PRESENT) &&
+ !get_page(pfn_to_page(new_hl2e >> PAGE_SHIFT), ed->domain) )
+ new_hl2e = 0;
+ if ( old_hl2e & _PAGE_PRESENT )
{
- if ( (new_hl2e & _PAGE_PRESENT) &&
- !shadow_get_page_from_l1e(mk_l1_pgentry(new_hl2e), ed->domain) )
- new_hl2e = 0;
- if ( old_hl2e & _PAGE_PRESENT )
- put_page_from_l1e(mk_l1_pgentry(old_hl2e), ed->domain);
+ put_page(pfn_to_page(old_hl2e >> PAGE_SHIFT));
+ need_flush = 1;
}
-
- ed->arch.hl2_vtable[l2_table_offset(va)] = mk_l1_pgentry(new_hl2e);
}
- ed->arch.guest_vtable[l2_table_offset(va)] = mk_l2_pgentry(value);
+ ed->arch.hl2_vtable[l2_table_offset(va)] = mk_l1_pgentry(new_hl2e);
+
+ if ( need_flush )
+ {
+ perfc_incrc(update_hl2e_invlpg);
+ __flush_tlb_one(&linear_pg_table[l1_linear_offset(va)]);
+ }
}
+
/************************************************************************/
-//#define MFN3_TO_WATCH 0x1ff6e
+//#define MFN3_TO_WATCH 0x8575
#ifdef MFN3_TO_WATCH
#define get_shadow_ref(__s) ( \
{ \
PERFCOUNTER_CPU(remove_write_bad_prediction, "remove_write bad prediction")
PERFCOUNTER_CPU(write_fault_bail, "sf bailed due to write_fault")
PERFCOUNTER_CPU(read_fault_bail, "sf bailed due to read_fault")
+PERFCOUNTER_CPU(update_hl2e_invlpg, "update_hl2e calls invlpg")